package core;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import projectiles.Projectile;
import towers.Cannon;
import towers.Tower;
import enemies.Enemy;
import towers.Plasmagun;


/**
 * @author Arno de Jager, Victor Jimenez Kwast
 * @version 1.1
 * @since 2011-04-11
 */
public class View extends JPanel implements Observer {

	private Model model;
	private ViewMenu east;
	private NextWavePanel waveInfo;
	private Mouse mouse;

	/**
	 * 
	 * @param m het model
	 * @param c de controller
	 */
	/* /// Constructor //////////////////////////////////////// */
	public View(Model m, Controller c) {
		this.model = m;

		JPanel center = new JPanel(new BorderLayout());
		JPanel battlefield = new BattlefieldView();
		mouse = c.getMouse();
		battlefield.addMouseListener(mouse);
		battlefield.addMouseMotionListener(mouse);

		east = new ViewMenu(m, c);
		waveInfo = new NextWavePanel();

		// Bepaling van layout
		this.setLayout(new BorderLayout());
		add(center, BorderLayout.CENTER);
		add(east, BorderLayout.EAST);

		// Linker deel
		center.add(battlefield, BorderLayout.CENTER);
		center.add(waveInfo, BorderLayout.SOUTH);
	}

	/* /// update //////////////////////////////////////// */
	public void update(Observable o, Object arg) {
		// Update ook menu
		if (arg.equals("updateStats"))
			east.update(o, arg);

		// Er is iets veranderd, repaint alles!
		else if (arg.equals("repaint"))
			repaint();

		// Next wave info moet aangepast worden
		else if (arg.equals("nextwave"))
			waveInfo.update(o, arg);
		else if (arg.equals("highscore"))
			showHighScore();
	}

	/* /// showHighScore //////////////////////////////////////// */
	public void showHighScore() {
		DB.DBspel.createConnection();
		String arr[][] = DB.DBspel.getBest(model.getMap().getID());

		StringBuffer s = new StringBuffer();
		for (int i = 0; i < arr.length; i++) {
			// for( int j = 0; j < arr[i].length; j++ ){
			s.append(arr[i][0] + " \t");
			s.append(arr[i][3] + " \t");
			// }
			s.append("\n");
		}
		DB.DBspel.shutdown();
		JOptionPane.showMessageDialog(this, "Highscore\nName Email Map Score\n" + s.toString());

	}

	class BattlefieldView extends JPanel {

		/* /// drawTowers //////////////////////////////////////// */
		public void drawTowers(Graphics g, Rectangle area, Component c) {
			for (Tower t : model.getTowers()) {
				Graphics2D g2d = (Graphics2D) g;
				if (!t.isOutsideView()) {
					if (t instanceof Cannon) {
						Cannon cannon = (Cannon) t;
						g2d.drawImage(cannon.getPlatformImage().getImage(), (int) cannon.getPosition().x,
								(int) cannon.getPosition().y, c);
					}
					if (t instanceof Plasmagun) {
						Plasmagun plasmagun = (Plasmagun) t;
						g2d.drawImage(plasmagun.getPlatformImage().getImage(), (int) plasmagun.getPosition().x,
								(int) plasmagun.getPosition().y, c);
					}

					if (t.viewAngle == 0)
						g.drawImage(t.getImage().getImage(), (int) t.position.x, (int) t.position.y, c);
					else {
						g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
								RenderingHints.VALUE_INTERPOLATION_BICUBIC);

						AffineTransform oldForm = g2d.getTransform();
						AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();

						newForm.rotate(Math.toRadians(t.viewAngle), (int) t.getMiddle().x, (int) t.getMiddle().y);

						g2d.setTransform(newForm);
						g2d.drawImage(t.getImage().getImage(), (int) t.position.x, (int) t.position.y, c);
						g2d.setTransform(oldForm);
					}
				}
			}
		}

		/* /// drawEnemies //////////////////////////////////////// */
		public void drawEnemies(Graphics g, Rectangle area, Component c) {
			for (Enemy e : model.getEnemies()) {
				Graphics2D g2d = (Graphics2D) g;
				if (!e.isOutsideView()) {
					if (e.viewAngle == 0)
						g.drawImage(e.getImage().getImage(), (int) e.position.x, (int) e.position.y, c);
					else {
						g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
								RenderingHints.VALUE_INTERPOLATION_BICUBIC);

						AffineTransform oldForm = g2d.getTransform();
						AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();

						newForm.rotate(Math.toRadians(e.viewAngle), (int) e.getMiddle().x, (int) e.getMiddle().y);

						g2d.setTransform(newForm);
						g2d.drawImage(e.getImage().getImage(), (int) e.position.x, (int) e.position.y, c);
						g2d.setTransform(oldForm);
					}
				}
				g.setColor(Color.BLACK);
				g.setFont(new Font("Arial", Font.PLAIN, 9));
				g.drawString(Math.round((e.getHealth() / (double) e.getMaxHealth() * 100)) + "%",
						(int) e.getPosition().x - 4, (int) e.getPosition().y + 1);
				g.setColor(Color.WHITE);
				g.setFont(new Font("Arial", Font.PLAIN, 9));
				g.drawString(Math.round((e.getHealth() / (double) e.getMaxHealth() * 100)) + "%",
						(int) e.getPosition().x - 5, (int) e.getPosition().y);
			}
		}

		/* /// drawProjectiles //////////////////////////////////////// */
		public void drawProjectiles(Graphics g, Rectangle area, Component c) {
			for (Projectile p : model.getProjectiles()) {
				Graphics2D g2d = (Graphics2D) g;
				if (!p.isOutsideView()) {
					if (p.viewAngle == 0)
						g.drawImage(p.getImage().getImage(), (int) p.position.x, (int) p.position.y, c);
					else {
						g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
								RenderingHints.VALUE_INTERPOLATION_BICUBIC);

						AffineTransform oldForm = g2d.getTransform();
						AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();

						newForm.rotate(Math.toRadians(p.viewAngle), (int) p.getMiddle().x, (int) p.getMiddle().y);

						g2d.setTransform(newForm);
						g2d.drawImage(p.getImage().getImage(), (int) p.position.x, (int) p.position.y, c);
						g2d.setTransform(oldForm);
					}
				}
			}
		}

		/* /// drawExplosions //////////////////////////////////////// */
		public void drawExplosions(Graphics g, Rectangle area, Component c) {
			for (Explosion ex : model.getExplosions()) {
				if (ex.getExplosionFrameNumber() < ex.getTillExplosionFrameNumber()) {
					ex.increaseExplosionFrameNumber();
					g.setColor(Color.YELLOW);
					g.fillOval(ex.getPosition().x - 4 * ex.getExplosionFrameNumber(),
							ex.getPosition().y - 2 * ex.getExplosionFrameNumber(), 8 * ex.getExplosionFrameNumber(),
							4 * ex.getExplosionFrameNumber());

					g.setColor(Color.RED);
					g.fillOval(ex.getPosition().x - 2 * ex.getExplosionFrameNumber(),
							ex.getPosition().y - ex.getExplosionFrameNumber() / 2, 4 * ex.getExplosionFrameNumber(),
							ex.getExplosionFrameNumber());
				}
			}
		}

		/* /// drawMap //////////////////////////////////////// */
		public void drawMap(Graphics g, Rectangle area, Component c) {
			Map map = model.getMap();
			Graphics2D g2 = (Graphics2D) g;
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

			// Teken achtergrond
			g.drawImage(map.getBackground().getImage(), 0, 0, area.width, area.height, c);

			// Teken routes
			for (ArrayList<Point2D.Double> route : map.getRoutes()) {

				// Teken punten
				Point2D.Double prevPoint = null;
				for (Point2D.Double p : route) {

					// We tekenen de route per 2 punten
					if (prevPoint != null) {
						g2.setColor(new Color(107, 130, 139));

						Polygon polygon = new Polygon();
						polygon.addPoint((int) prevPoint.x, (int) prevPoint.y);
						polygon.addPoint((int) prevPoint.x, (int) (prevPoint.y + Map.wayWidth));
						polygon.addPoint((int) p.x, (int) (p.y + Map.wayWidth));
						polygon.addPoint((int) p.x, (int) p.y);
						g2.fillPolygon(polygon);

						g2.setColor(Color.WHITE);
						g2.drawLine((int) p.x, (int) p.y, (int) prevPoint.x, (int) prevPoint.y);
						g2.drawLine((int) p.x, (int) (p.y + Map.wayWidth), (int) prevPoint.x,
								(int) (prevPoint.y + Map.wayWidth));

						map.getPolygonArray().add(polygon);
					}
					prevPoint = p;
				}
			}

			// Teken base
			drawBase(g, area, c);

		}

		/* /// drawBase //////////////////////////////////////// */
		public void drawBase(Graphics g, Rectangle area, Component c) {
			Base base = model.getMap().getBase();
			if (!base.isOutsideView()) {
				if (base.viewAngle == 0)
					g.drawImage(base.getImage().getImage(), (int) base.position.x, (int) base.position.y, c);
				else {
					Graphics2D g2d = (Graphics2D) g;
					g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

					AffineTransform oldForm = g2d.getTransform();
					AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();

					newForm.rotate(Math.toRadians(base.viewAngle), (int) base.getMiddle().x, (int) base.getMiddle().y);

					g2d.setTransform(newForm);
					g2d.drawImage(base.getImage().getImage(), (int) base.position.x, (int) base.position.y, c);
					g2d.setTransform(oldForm);
				}
			}

			int hpLeft = base.maxHealth - base.health;

			// 5 rondjes boven
			int x = 6;
			for (int i = 0; i < 6; i++) {
				if (hpLeft > 0) {
					hpLeft--;
					g.setColor(Color.RED);
				} else
					g.setColor(Color.GREEN);

				g.fillOval((int) base.position.x + x, (int) base.position.y + 6, 11, 11);
				g.setColor(Color.BLACK);
				g.drawOval((int) base.position.x + x, (int) base.position.y + 6, 11, 11);

				x += 13;
			}

			// 3 rondjes rechts
			int y = 19;
			for (int i = 0; i < 3; i++) {
				if (hpLeft > 0) {
					hpLeft--;
					g.setColor(Color.RED);
				} else
					g.setColor(Color.GREEN);
				g.fillOval((int) base.position.x + 71, (int) base.position.y + y, 11, 11);
				g.setColor(Color.BLACK);
				g.drawOval((int) base.position.x + 71, (int) base.position.y + y, 11, 11);

				y += 13;
			}

			// 6 rondjes beneden
			x = 71;
			for (int i = 0; i < 6; i++) {
				if (hpLeft > 0) {
					hpLeft--;
					g.setColor(Color.RED);
				} else
					g.setColor(Color.GREEN);
				g.fillOval((int) base.position.x + x, (int) base.position.y + 58, 11, 11);
				g.setColor(Color.BLACK);
				g.drawOval((int) base.position.x + x, (int) base.position.y + 58, 11, 11);

				x -= 13;
			}

			// 3 rondjes links
			y = 45;
			for (int i = 0; i < 3; i++) {
				if (hpLeft > 0) {
					hpLeft--;
					g.setColor(Color.RED);
				} else
					g.setColor(Color.GREEN);
				g.fillOval((int) base.position.x + 6, (int) base.position.y + y, 11, 11);
				g.setColor(Color.BLACK);
				g.drawOval((int) base.position.x + 6, (int) base.position.y + y, 11, 11);

				y -= 13;
			}

			// 2 rondjes midden
			x = 32;
			for (int i = 0; i < 2; i++) {
				if (hpLeft > 0) {
					hpLeft--;
					g.setColor(Color.RED);
				} else
					g.setColor(Color.GREEN);

				g.fillOval((int) base.position.x + x, (int) base.position.y + 32, 11, 11);
				g.setColor(Color.BLACK);
				g.drawOval((int) base.position.x + x, (int) base.position.y + 32, 11, 11);

				x += 13;
			}
		}

		/* /// paintComponent //////////////////////////////////////// */
		public void paintComponent(Graphics g) {
			drawMap(g, this.getBounds(), this);
			drawTowers(g, this.getBounds(), this);
			drawEnemies(g, this.getBounds(), this);
			drawProjectiles(g, this.getBounds(), this);
			drawExplosions(g, this.getBounds(), this);

			// Eventueel pause-icon
			if (model.isPaused())
				g.drawImage(new ImageIcon("images/pause.gif").getImage(), 5, 5, this);

			// mouse actie tekenen
			// controleren op nieuw geselecteerde tower
			if (mouse.getSelectedItem() != null && mouse.getSelectedItem().position == null) {
				Point point = mouse.getMouseDot();
				// controleren of plek bezet is, en kleur toekennen
				if (mouse.placeOccupied(point)) {
					g.setColor(Color.RED);
				} else {
					g.setColor(Color.GREEN);
				}
				// we moeten nu schaduw tekenen op veld
				g.drawRect(point.x - mouse.getSelectedItem().getImage().getIconHeight() / 2, point.y
						- mouse.getSelectedItem().getImage().getIconWidth() / 2, mouse.getSelectedItem().getImage()
						.getIconWidth(), mouse.getSelectedItem().getImage().getIconHeight());
			} else if (mouse.getSelectedItem() != null && mouse.getSelectedItem().position != null) {
				// er is een bestaande tower geselecteerd, vierkant eromheen
				// tekenen.
				Point2D.Double point = mouse.getSelectedItem().position;
				g.setColor(Color.WHITE);
				g.drawRect((int) point.getX() - 3, (int) point.getY() - 3, mouse.getSelectedItem().getImage()
						.getIconWidth() + 6, mouse.getSelectedItem().getImage().getIconHeight() + 6);

			}
		}
	}

	class NextWavePanel extends JPanel {
		WaveInfo left = new WaveInfo(false);
		WaveInfo right = new WaveInfo(true);

		/* /// Constructor //////////////////////////////////////// */
		public NextWavePanel() {
			setLayout(new GridLayout(1, 2));
			setPreferredSize(new Dimension(Model.battlefieldWidth, 60));
			setBackground(new Color(60, 79, 104));

			add(createPart("Second Wave", left));
			add(createPart("First Wave", right));
		}

		/* /// createPart //////////////////////////////////////// */
		private JPanel createPart(String strTitle, JPanel content) {
			JPanel title = new JPanel();
			title.setBackground(Color.black);

			JLabel titleLabel = new JLabel(strTitle);
			titleLabel.setForeground(Color.white);
			titleLabel.setFont(new Font("Verdana", Font.BOLD, 12));
			title.add(titleLabel);

			JPanel x = new JPanel(new BorderLayout());
			x.setBackground(new Color(60, 79, 104));
			x.add(title, BorderLayout.NORTH);
			x.add(content, BorderLayout.CENTER);

			return x;
		}

		/* /// update //////////////////////////////////////// */
		public void update(Observable o, Object arg) {
			left.update(o, arg);
			right.update(o, arg);
		}

		class WaveInfo extends JPanel {
			private String filename = "images/infantry.gif";
			private boolean firstWave;

			/* /// Constructor //////////////////////////////////////// */
			public WaveInfo(boolean firstWave) {
				this.firstWave = firstWave;

				String waveType;

				if (this.firstWave) {
					waveType = model.getFirstWave();
				} else {
					waveType = model.getSecondWave();
				}

				System.out.println(waveType);

				if (waveType.equals("Infantry"))
					filename = "images/infantry.gif";
				else if (waveType.equals("Jeep"))
					filename = "images/jeep.gif";
				else if (waveType.equals("Tank"))
					filename = "images/tank.gif";
			}

			/* /// paintComponent //////////////////////////////////////// */
			public void paintComponent(Graphics g) {
				// Aantal units
				g.setColor(Color.WHITE);
				g.setFont(new Font("Tahoma", Font.BOLD, 12));

				int level = model.getStats().getLevel() + 1;
				if (!this.firstWave)
					level++;

				int aantalEnemies = model.getCountEnemies(level);
				g.drawString(aantalEnemies + " unit" + (aantalEnemies == 1 ? "" : "s"), 160, 20);

				// 3 plaatjes van type vijand
				ImageIcon enemy = new ImageIcon(filename);
				int x = 240;

				Graphics2D g2d = (Graphics2D) g;
				g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

				AffineTransform oldForm = g2d.getTransform();
				AffineTransform newForm = (AffineTransform) g2d.getTransform().clone();

				newForm.rotate(Math.toRadians(90), x, 7);

				g2d.setTransform(newForm);
				g2d.drawImage(enemy.getImage(), x, 0, this);
				g2d.setTransform(oldForm);
			}

			/* /// update //////////////////////////////////////// */
			public void update(Observable o, Object arg) {
				String waveType;

				if (this.firstWave) {
					waveType = model.getFirstWave();
				} else {
					waveType = model.getSecondWave();
				}

				if (waveType.equals("Infantry"))
					filename = "images/infantry.gif";
				else if (waveType.equals("Jeep"))
					filename = "images/jeep.gif";
				else if (waveType.equals("Tank"))
					filename = "images/tank.gif";
			}
		}
	}
}
